package com.zhuangjie.redis.helper;

import com.zhaungjie.base.utils.DebounceExecutor;
import com.zhuangjie.redis.entity.RedisGeo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * redis地理助手
 *
 * @author zhuangjie
 * @date 2024/01/19
 */
@Component
public class RedisGeoHelper {
    private final DebounceExecutor putDebounceExecutor = new DebounceExecutor(100); // x毫秒的防抖延迟
    private final Map<String, Set<RedisGeo>> putKeyPointMap = new HashMap<>();
    @Autowired
    private RedisTemplate redisTemplate;

    public void put(RedisGeo redisGeo) {
        if (redisGeo == null || !redisGeo.checkInvalid()) {
            return;
        }
        Set<RedisGeo> points = putKeyPointMap.get(redisGeo.getKey());
        if (points == null) putKeyPointMap.put(redisGeo.getKey(), points = new HashSet<>());
        points.add(redisGeo);
        putDebounceExecutor.debounce(() -> {
            for (Map.Entry<String, Set<RedisGeo>> entry : putKeyPointMap.entrySet()) {
                try {
                    Map<String, Point> putPoints = entry.getValue().stream().filter(_redisGeo->_redisGeo.getLatitude() != null && _redisGeo.getLongitude() != null).collect(Collectors.toMap(_redisGeo -> redisGeo.getMember(), _redisGeo -> new Point(redisGeo.getLongitude(), redisGeo.getLatitude())));
                    redisTemplate.opsForGeo().add(entry.getKey(), putPoints);
                    putKeyPointMap.remove(entry.getKey());
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("出现Redis Geo put异常:" + e.getMessage());
                }
            }
        });
    }

    /**
     * 移除指定的单个坐标
     * @param key
     * @param member
     */
    public void remove(String key, String member) {
        if (member == null) return;
        redisTemplate.opsForGeo().remove(key,member);
    }

    /**
     * 查询指定坐标的位置信息
     *
     * @return
     */
    public Point get(String key, String member) {
        List<Point> position = redisTemplate.opsForGeo().position(key, member);
        if (position == null || position.isEmpty()) {
            return null;
        }
        return position.get(0);
    }



    /**
     * 查找指定中心点指定半径内最近的指定个数
     * @param key
     * @param longitude
     * @param latitude
     * @param radius 查找半径（单位：公里）
     * @param count
     * @return
     */
    public GeoResults<RedisGeoCommands.GeoLocation<String>> findNearby(String key,Double longitude,Double  latitude,Double radius,Integer count) {
        Circle circle = new Circle(new Point(longitude,latitude), new Distance(radius, Metrics.KILOMETERS));//Point(经度, 纬度) Distance(距离量, 距离单位)
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(count);
        return redisTemplate.opsForGeo().radius(key, circle, args);
    }
}
